﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Glue.Internals.PrintTool
{
    internal class PrintTool<T1,T2>
    {
        private readonly Mapping<T1, T2> mapping;

        public PrintTool(Mapping<T1,T2> mapping)
        {
            this.mapping = mapping;
        }

        public RelationReport GetReport()
        {
            var report = new RelationReport(typeof(T1),typeof(T2));
            var relations = mapping.Relations.GetAllRelations();
            LoopRelations(relations, report,"","");
            return report;
        }

        private void LoopRelations(IEnumerable<IRelation> relations, RelationReport report, String leftPropertyPrefix, String rightPropertyPrefix)
        {
            foreach (var relation in relations)
            {
                if (relation.LeftMember is IRepresentBaseObject || relation.RightMember is IRepresentBaseObject)
                    AddNestedRelation(report, relation, leftPropertyPrefix, rightPropertyPrefix);
                else if (relation.LeftMember is INestedMember && relation.RightMember is INestedMember)
                    AddNestedRelation(report, relation, leftPropertyPrefix, rightPropertyPrefix);
                else
                    report.AddLine(new ReportLine(relation, leftPropertyPrefix, rightPropertyPrefix));
            }
        }

        private void AddNestedRelation(RelationReport report, IRelation flattenedRelation, String leftPropertyPrefix, String rightPropertyPrefix)
        {
            var leftPrefix = leftPropertyPrefix + flattenedRelation.LeftMember.Name + ".";
            var rightPrefix = rightPropertyPrefix + flattenedRelation.RightMember.Name + ".";
            if (flattenedRelation.LeftMember is IRepresentBaseObject) leftPrefix = leftPropertyPrefix;
            if (flattenedRelation.RightMember is IRepresentBaseObject) rightPrefix = rightPropertyPrefix;
            var converter = flattenedRelation.GetConverter() as IHoldNestedRelation;
            LoopRelations(converter.GetAllRelations(), report, leftPrefix,rightPrefix);
        }

        public void Print(RelationReport report, Action<String> writeLine)
        {
            var arrowMinLength = 3;
            var totalSize = report.LeftColumnSize + report.RightColumnSize + arrowMinLength;
            
            writeLine(report.LeftTypeName + " " 
                + GetTextArrow(RelationDirection.TwoWays, totalSize - report.LeftTypeName.Length - report.RightColumnSize) + 
                " " + report.RightTypeName);
            writeLine(GetRulerOfLength(totalSize + 2));

            foreach (var reportLine in report.GetLines())
            {
                writeLine(reportLine.LeftSidePropertyName + " " +
                    GetTextArrow(reportLine.Direction, totalSize - reportLine.LeftSidePropertyName.Length - report.RightColumnSize) + 
                    " " + reportLine.RightSidePropertyName);
            }
        }

        public void Print_old(RelationReport report, Action<String> writeLine)
        {
            var arrowMinLength = 3;
            var totalSize = report.LeftColumnSize + report.RightColumnSize + arrowMinLength;

            writeLine(report.LeftTypeName + " "
                + GetTextArrow(RelationDirection.TwoWays, totalSize - report.LeftTypeName.Length - report.RightTypeName.Length) +
                " " + report.RightTypeName);
            writeLine(GetRulerOfLength(totalSize + 2));

            foreach (var reportLine in report.GetLines())
            {
                writeLine(reportLine.LeftSidePropertyName + " " +
                    GetTextArrow(reportLine.Direction, totalSize - reportLine.LeftSidePropertyName.Length - reportLine.RightSidePropertyName.Length) +
                    " " + reportLine.RightSidePropertyName);
            }

        }

        private string GetRulerOfLength(int length)
        {
            var builder = new StringBuilder(length);
            for (int i = 0; i < length; i++)
            {
                builder.Append("-");
            }
            return builder.ToString();
        }

        private string GetTextArrow(RelationDirection direction, int Length)
        {
            if (direction == RelationDirection.TowardsLeft)
                return "<" + GetRulerOfLength(Length-1);
            if (direction == RelationDirection.TowardsRight)
                return GetRulerOfLength(Length-1) + ">";
            return "<"+GetRulerOfLength(Length-2)+">";
        }
    }
}
